package com.nlabs.slickgwt.client;

 
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.HasMouseDownHandlers;
import com.google.gwt.event.dom.client.HasMouseMoveHandlers;
import com.google.gwt.event.dom.client.HasMouseUpHandlers;
import com.google.gwt.event.dom.client.MouseDownEvent;
import com.google.gwt.event.dom.client.MouseDownHandler;
import com.google.gwt.event.dom.client.MouseMoveEvent;
import com.google.gwt.event.dom.client.MouseMoveHandler;
import com.google.gwt.event.dom.client.MouseOutEvent;
import com.google.gwt.event.dom.client.MouseOutHandler;
import com.google.gwt.event.dom.client.MouseOverEvent;
import com.google.gwt.event.dom.client.MouseOverHandler;
import com.google.gwt.event.dom.client.MouseUpEvent;
import com.google.gwt.event.dom.client.MouseUpHandler;
import com.google.gwt.event.logical.shared.ResizeEvent;
import com.google.gwt.event.logical.shared.ResizeHandler;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.ui.DecoratedPopupPanel;
import com.google.gwt.user.client.ui.FlexTable;
import com.google.gwt.user.client.ui.FocusPanel;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.HasHorizontalAlignment;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.PopupPanel;
import com.google.gwt.user.client.ui.SimplePanel;
import com.google.gwt.user.client.ui.Widget;


public class Window extends DecoratedPopupPanel implements ResizeHandler {
	   
	   private int m_x = 0;
	   private int m_y = 0; 
	   private int m_width = 0; 
	   private int m_height = 0; 
	   private int m_start_drag_x = 0;
	   private int m_start_drag_y = 0; 
	   private int m_x_before_max = 0; 
	   private int m_y_before_max = 0; 
	   private int m_min_height = 100;
	   private int m_min_width = 100; 
	   private boolean m_dragging = false;
	   private boolean m_dragpolicy = true; 
	   private boolean m_draggable = true;
	   private boolean m_resize_start = false; 
	   private boolean m_resizing = false;
	   private boolean m_resizable = true;
	   private boolean m_resizepolicy = true; 
	  
	   private static PopupPanel resize_shadow = new PopupPanel(); 
	   private enum WindowState {NORMAL, MAXIMIZED};
	   private WindowState m_windowstate = WindowState.NORMAL; 
	   private WindowResizeMouseHandler resizehandler = new WindowResizeMouseHandler(); 
	   private FlexTable m_table = new FlexTable();  
	   private FocusPanel m_top_left = new FocusPanel(); 
	   private FocusPanel m_top_right = new FocusPanel();
	   private FocusPanel m_left_border = new FocusPanel();
	   private FocusPanel m_right_border = new FocusPanel();
	   private FocusPanel m_bottom_border = new FocusPanel();
	   private FocusPanel m_bottom_left = new FocusPanel();
	   private FocusPanel m_bottom_right = new FocusPanel(); 
	   
	   
	   protected WindowCaption m_caption = new WindowCaption(this);
	   protected SimplePanel m_body = new SimplePanel(); 
	   
	   
		public Window() {
		  
			m_table.setWidth("100%");
			m_table.setHeight("100%");
			m_table.setBorderWidth(0);
			m_table.setCellPadding(0);
			m_table.setCellSpacing(0);
		
			m_caption.addMouseUpHandler(new MouseUpHandler()  {

				public void onMouseUp(MouseUpEvent event) {
					
					m_dragging=false;
					m_resizing=false; 
					m_resize_start = false; 
					DOM.releaseCapture(m_caption.getElement());
					 
				}
			});
			
			m_caption.addMouseDownHandler(new MouseDownHandler() {

				public void onMouseDown(MouseDownEvent event) {
					
					resize_shadow.hide(); 
					if(m_draggable){
						
						m_start_drag_x = event.getX();
						m_start_drag_y = event.getY(); 
						m_dragging = true; 
					 } 
					 
					DOM.setCapture(m_caption.getElement());
				} 
			 
			});
			
			m_caption.addMouseMoveHandler(new MouseMoveHandler() {

				public void onMouseMove(MouseMoveEvent event) {
					 
					if(m_dragging){ 
						
						DOM.setStyleAttribute(m_caption.getElement(), "cursor", "move");
						m_x = event.getClientX()   ;
						m_y = event.getClientY()   ;
						setPopupPosition(Math.max(m_x - m_start_drag_x, 0), Math.max(m_y - m_start_drag_y,0));
					 
					}
					 
					else if(m_draggable){
						DOM.setStyleAttribute(m_caption.getElement(), "cursor", "move");
					}
					else{
						DOM.setStyleAttribute(m_caption.getElement(), "cursor", "default");
					}
				}
  
			}) ;
		 
			m_top_left.setStylePrimaryName("slick-window-top-corner");
			m_top_left.setSize("100%", "100%");
			 
			 
			m_top_right.setStylePrimaryName("slick-window-top-corner");
			m_top_right.setSize("100%", "100%"); 
			 
			
			m_left_border.setStylePrimaryName("slick-window-border-left");
			m_left_border.setSize("6px", "100%");
			 
			
			m_right_border.setStylePrimaryName("slick-window-border-right");
			m_right_border.setSize("6px", "100%");
			 
			
			m_bottom_border.setStylePrimaryName("slick-window-border-bottom");
			m_bottom_border.setSize("100%", "6px");
			 
			
			m_bottom_left.setStylePrimaryName("slick-window-border-leftcorner");
			m_bottom_left.setSize("6px", "6px");
			 
		 
			m_bottom_right.setStylePrimaryName("slick-window-border-rightcorner");
			m_bottom_right.setSize("6px", "6px");
			m_bottom_right.setWidget(new Image("resources/window_resize.gif"));
			m_bottom_right.addMouseMoveHandler(resizehandler);
			m_bottom_right.addMouseDownHandler(resizehandler);
			m_bottom_right.addMouseUpHandler(resizehandler);
			if(SlickGWT.getUserAgent().contains("msie")){
				
				DOM.setStyleAttribute(m_bottom_right.getElement(), "padding", "10px 0 0 0");
				m_bottom_right.setHeight("100%");
				m_right_border.setWidth("7px");
			}
			else{
				
				DOM.setStyleAttribute(m_bottom_right.getElement(), "padding", "0px");
			}
			
			m_body.setStylePrimaryName("slick-window-body");
			m_body.setSize("100%", "100%");
			DOM.setStyleAttribute(m_body.getElement(), "padding", "0px"); 
			resize_shadow.setWidget(new SimplePanel());
			DOM.setStyleAttribute(resize_shadow.getElement(), "border", "1px dotted black");
			DOM.setStyleAttribute(resize_shadow.getElement(), "background", "transparent");
			com.google.gwt.user.client.Window.addResizeHandler(this);
			setStylePrimaryName("slick-window");
			layout(); 
			setWidget(m_table);
		}
		
		public void setWidget(Widget w){
			
			if(w.equals(m_table)){
				super.setWidget(w);
			}
			else{
				
				m_body.setWidget(w);
		 
			}
		}
		
		private void layout() {
			
			m_table.setWidget(0, 0, m_top_left); 
			m_table.setWidget(0, 1, m_caption);
			m_table.setWidget(0, 2, m_top_right);
			m_table.setWidget(1, 0, m_left_border); 
			m_table.setWidget(1, 1, m_body); 
			m_table.setWidget(1, 2, m_right_border);
			m_table.setWidget(2, 0, m_bottom_left);
			m_table.setWidget(2, 1, m_bottom_border);
			m_table.setWidget(2, 2, m_bottom_right);
		}
		
		private void fitWindowToResize() {
			
			m_width = resize_shadow.getOffsetWidth()  - m_caption.getPadding() - 6;
			m_height = resize_shadow.getOffsetHeight() - m_caption.getOffsetHeight() - 6;
			//adjust for ie qwirk
			if(SlickGWT.getUserAgent().contains("msie")){
				m_height = m_height - 14; 
			}
			 
			m_body.getWidget().setSize("" + m_width, "" + m_height);
			layout();
			setPopupPosition(resize_shadow.getPopupLeft(), resize_shadow.getPopupTop());
			resize_shadow.hide(); 
		
		}
		
		private void showResizeShadow(int w, int h, int x, int y) {
			 
			w = w - 8;
			h = h - 8; 
			resize_shadow.setPopupPosition(x, y);
			resize_shadow.setSize("" +w, "" + h);
			resize_shadow.show(); 
			
			
		}
		 
		public void setDraggable(boolean b){
			
			m_dragpolicy = b; 
		}
		
		public void setResizable(boolean b){
			m_resizepolicy=b; 
		}
		
		public void setMaximizable(boolean b){
			
			m_caption.setMaximizable(b);
		}
		
		public void setClosable(boolean b){
			m_caption.setClosable(b);
		}
		
		public boolean onEventPreview(Event event) {
		    // We need to preventDefault() on mouseDown events (outside of the
		    // DialogBox content) to keep text from being selected when it
		    // is dragged.
		    if (DOM.eventGetType(event) == Event.ONMOUSEDOWN) {
		      if (DOM.isOrHasChild(getElement(), DOM.eventGetTarget(event))) {
		    	  		DOM.eventPreventDefault(event);
		      }
		    }
		    return true; 
		  }  
		
		public void close() {
			
			setWindowState(WindowState.NORMAL);
			hide(); 
			
		}
		
		public void show() {
			
			super.show(); 
			m_x_before_max = this.getPopupLeft();
			m_y_before_max = this.getPopupTop();
			m_draggable = m_dragpolicy; 
			m_width = Math.max(m_width, m_body.getWidget().getOffsetWidth());
			m_height = Math.max(m_height, m_body.getWidget().getOffsetHeight()); 
			m_body.getWidget().setSize("" + m_width, "" + m_height);
		}
	 
		public void center() {
		
			super.center(); 
			m_x_before_max = this.getPopupLeft();
			m_y_before_max = this.getPopupTop();
			m_draggable = m_dragpolicy; 
			m_width = Math.max(m_width, m_body.getWidget().getOffsetWidth());
			m_height = Math.max(m_height, m_body.getWidget().getOffsetHeight()); 
			m_body.getWidget().setSize("" + m_width, "" + m_height);
			 
		}

		public WindowState getWindowState(){
			
			return m_windowstate; 
		}
		
		public void setWindowState(WindowState windowstate) {
			
			 
			if(windowstate == WindowState.MAXIMIZED){
				
				m_x_before_max = this.getPopupLeft();
				m_y_before_max = this.getPopupTop();
				m_width = m_body.getOffsetWidth();
				m_height = m_body.getOffsetHeight();
				int w = com.google.gwt.user.client.Window.getClientWidth() - m_caption.getPadding() - 12 ;   
				int h = com.google.gwt.user.client.Window.getClientHeight() - m_caption.getOffsetHeight() - 12;
				//fix height problem in ie
				if(SlickGWT.getUserAgent().contains("msie")){
					h = h - 14; 
				}
				m_body.getWidget().setPixelSize(w,  h);
				layout();
				this.setPopupPosition(0, 0);
				m_windowstate = WindowState.MAXIMIZED; 
				m_draggable = false; 
				m_resizable = false; 
			}
			else if(windowstate == WindowState.NORMAL){
				
				int h = m_height ;
				int w = m_width ;
				m_body.getWidget().setPixelSize(w, h);
				setPopupPosition(m_x_before_max, m_y_before_max);
				m_windowstate = WindowState.NORMAL; 
				m_draggable = m_dragpolicy; 
				m_resizable = m_resizepolicy; 
				
			}
			 
		}
 
		public void setHeading(String t){
			m_caption.setHeading(t);
		}
 
		public void setSize(String width, String height){
			
			m_width = new Integer(width).intValue();
			m_height = new Integer(height).intValue(); 
			
		}
		 
	 
		public void onResize(ResizeEvent event) {
			 
			 if(getWindowState() == WindowState.MAXIMIZED){
				 
				 int w = com.google.gwt.user.client.Window.getClientWidth() - m_caption.getPadding() - 12 ;   
					int h = com.google.gwt.user.client.Window.getClientHeight() - m_caption.getOffsetHeight() - 12;
					//fix height problem in ie
					if(SlickGWT.getUserAgent().contains("msie")){
						h = h - 14; 
					}
					m_body.getWidget().setPixelSize(w,  h);
					layout(); 
					 
				  
			 }
			
		}
		
		private class WindowResizeMouseHandler implements MouseMoveHandler, MouseUpHandler, MouseDownHandler {
		
			
			WindowResizeMouseHandler() {
				super();
			}

			public void onMouseMove(MouseMoveEvent event) {
				
			   if(m_resizing || m_resize_start){
					
					  
					int x_shadow = getPopupLeft();
					int y_shadow = getPopupTop(); 
					int new_height = getOffsetHeight() + event.getY(); 
					//fix height problem in ie
					if(SlickGWT.getUserAgent().contains("msie")){
						new_height = new_height - 14; 
					}
					int new_width = getOffsetWidth() + event.getX(); 	 
					if(new_height < m_min_height){
							new_height = m_min_height; 	 
					}
					if(new_width < m_min_width) {
						new_width = m_min_width; 	 
					}
				  
					 
					showResizeShadow(new_width, new_height, x_shadow, y_shadow); 
					m_resizing = true;
			   }
			   if(m_resizable && event.getSource().equals(m_bottom_right)){
				   
				     if(event.getY() >= m_bottom_right.getOffsetHeight() - 6){
						   DOM.setStyleAttribute(m_bottom_right.getElement(), "cursor", "se-resize");
					   }
					   else{
						   DOM.setStyleAttribute(m_bottom_right.getElement(), "cursor", "default");	
					   }
   
			   }
			   else {
				   DOM.setStyleAttribute(((Widget) event.getSource()).getElement(), "cursor", "default");
			   }
				
			}

			public void onMouseUp(MouseUpEvent event) {
				
				if(m_resizing){
				   fitWindowToResize(); 
				}
				m_resizing = false;
				m_resize_start = false;
				DOM.releaseCapture(((Widget) event.getSource()).getElement());
				
			}

			public void onMouseDown(MouseDownEvent event) {
				 m_resize_start = true; 
				 DOM.setCapture(((Widget) event.getSource()).getElement()); 
				
			}
	 
		}
		
	 
		private class WindowCaption extends HorizontalPanel implements HasMouseDownHandlers, HasMouseMoveHandlers, HasMouseUpHandlers, MouseOverHandler, MouseOutHandler {

			 
			private HTML m_header_text = new HTML();
			private static final int icon_size = 14; 
			private final Image m_close_button = new Image(); 
			private final Image m_minmax_button = new Image(); 
			private final HorizontalPanel button_pane = new HorizontalPanel(); 
			private int padding = 5; 
			
			private Window m_parent = null; 
			
			
			public WindowCaption(Window w){
				
				m_parent = w; 
				DOM.setStyleAttribute(this.getElement(), "padding", "5px 0 5px 0");
				 
				setWidth("100%");
				setHeight("100%");
				m_header_text.setStylePrimaryName("slick-window-header");
				add(m_header_text);
				 
				setCellHorizontalAlignment(m_header_text, HasHorizontalAlignment.ALIGN_LEFT);
				
				m_close_button.setUrlAndVisibleRect("resources/toolicons.gif", 0,0, icon_size, icon_size);
				m_close_button.addMouseOverHandler(this);
				m_close_button.addMouseOutHandler(this);
				m_close_button.setStylePrimaryName("slick-window-button");
				
				m_minmax_button.setUrlAndVisibleRect("resources/toolicons.gif", 0,icon_size + 1, icon_size, icon_size);
				m_minmax_button.addMouseOverHandler(this);
				m_minmax_button.addMouseOutHandler(this);
				m_minmax_button.setStylePrimaryName("slick-window-button");
				
				m_minmax_button.addClickHandler(new ClickHandler() {

					public void onClick(ClickEvent event) {
						
						m_close_button.setUrlAndVisibleRect("resources/toolicons.gif", 0,0, icon_size, icon_size);
						m_minmax_button.setUrlAndVisibleRect("resources/toolicons.gif", 0,icon_size + 1, icon_size, icon_size);
						if(m_parent.getWindowState() == WindowState.NORMAL){
							m_parent.setWindowState(WindowState.MAXIMIZED); 
						}
						else {
							
							m_parent.setWindowState(WindowState.NORMAL); 
						} 
					} 
				});
				
				m_close_button.addClickHandler(new ClickHandler() {

					public void onClick(ClickEvent event) {
						
						m_close_button.setUrlAndVisibleRect("resources/toolicons.gif", 0,0, icon_size, icon_size);
						m_minmax_button.setUrlAndVisibleRect("resources/toolicons.gif", 0,icon_size + 1, icon_size, icon_size);
						m_parent.close();  
					} 	
				});
				
				button_pane.add(m_minmax_button);
				button_pane.setCellWidth(m_minmax_button, "18px");
				button_pane.add(m_close_button);
		
				add(button_pane);
				setCellHorizontalAlignment(button_pane, HasHorizontalAlignment.ALIGN_RIGHT);
				
				setStylePrimaryName("slick-window-top"); 
			}
			
			public void setHeading(String t) {

				m_header_text.setHTML(t);
				
			} 
			
			public void setMaximizable(boolean b){
				
				if(!b){
					button_pane.remove(m_minmax_button);
				}
				
			}
			
			public void setClosable(boolean b){
				
				if(!b){
					button_pane.remove(m_close_button);
				}
			}
			
			public int getPadding() {
				return padding; 
			}
			
			public HandlerRegistration addMouseDownHandler(MouseDownHandler handler) {
				return addDomHandler(handler, MouseDownEvent.getType());

			}
		 
			public HandlerRegistration addMouseMoveHandler(MouseMoveHandler handler) {
				return addDomHandler(handler, MouseMoveEvent.getType());
			}
			
			 
			public HandlerRegistration addMouseUpHandler(MouseUpHandler handler) {
				return addDomHandler(handler, MouseUpEvent.getType());
			}

			public void onMouseOver(MouseOverEvent event) {
				if(event.getSource().equals(m_close_button)){
					m_close_button.setUrlAndVisibleRect("resources/toolicons.gif", icon_size + 1,0, icon_size, icon_size);
				}
				else if(event.getSource().equals(m_minmax_button)){
			
					m_minmax_button.setUrlAndVisibleRect("resources/toolicons.gif", icon_size + 1, icon_size + 1, icon_size, icon_size);
				}
			}

			public void onMouseOut(MouseOutEvent event) {
				if(event.getSource().equals(m_close_button)){ 
					m_close_button.setUrlAndVisibleRect("resources/toolicons.gif", 0,0, icon_size, icon_size);
				}
				else if(event.getSource().equals(m_minmax_button)){
					
					m_minmax_button.setUrlAndVisibleRect("resources/toolicons.gif", 0,icon_size + 1, icon_size, icon_size);
				}
			}

		}


	
 		 
}
